/* @(#)wrapesms.cc
 * Time-stamp: <2009-02-26 00:52:17 root>
 * Copyright 2008 Julian Qian
 * Author: root@localhost.localdomain
 * Version: $Id: wrapesms.cc,v 0.0 2008/11/08 06:01:53 root Exp $
 * Keywords: 
 */



// #include "soap.nsmap"
#include "EsmsServiceSoap.nsmap"

#include "wrapesms.hh"
#include "../common.hh"
#include "../inifile.hh"
#include "../excep.hh"
#include "../mutex.hh"

#include <iostream>
#include <iomanip>


using std::string;
using std::cout;
using std::endl;
using std::vector;

Wrapesms* Wrapesms::_theWrapesms = NULL;

Wrapesms*
Wrapesms::initWrapesms(MsgList* pmlist){
    if(NULL == _theWrapesms){
        _theWrapesms = new Wrapesms(pmlist);
    }else{
        throw EsmsInitFailed("initWrapesms");
    }
}

Wrapesms*
Wrapesms::theWrapesms(){
    if(NULL == _theWrapesms){
        throw EsmsInitFailed("theWrapesms");
    }
    return _theWrapesms;
}

void
Wrapesms::endWrapesms(){
    delete _theWrapesms;
}

// construct function
Wrapesms::Wrapesms(MsgList *pmlist){

    _pmlist = pmlist;

    _mutsms = new MutEX(RECU);

    taskCode = 1;

    Config *cnf = Config::theConfig(GEN_CONF_FILE);

    username = cnf->read("ESMS","USERNAME");
    password = cnf->read("ESMS","PASSWORD");
    phonecode = cnf->read("ESMS","PHONECODE");
    servcode = cnf->read("ESMS","SERVECODE");
    
    if(username.empty()  ||
       password.empty()  ||
       phonecode.empty() ||
       servcode.empty()){
        throw ConfigError("ESMS server configure error");
    }    

    string disstr = cnf->read("ESMS", "DISABLED");

    if( 0 == disstr.compare("YES") ){
        _disabled = true;
        return;
    }
    
    _disabled = false;

    service = new EsmsServiceSoapProxy(SOAP_IO_KEEPALIVE);

    // _msgList = new MsgVector;

    login();
}

Wrapesms::~Wrapesms(){
    // delete _msgList;
    delete _mutsms;
    if(! _disabled){
        clear();
        delete service;
    }
}

bool
Wrapesms::login(){
    if(_disabled)    throw EsmsDisabled("Login");
    
    _ns1__Login l;
    _ns1__LoginResponse r;
    l.userName = &username;
    l.password = &password;

    int rec = 0;
START_LOGIN:
    if(service->Login(&l, &r) == SOAP_OK){
        switch(r.LoginResult){
        case LOGIN_OK:
            cout << "ESMS Login OK!" <<endl;
            return true;
        case LOGIN_EXCEPT:
            // re-connect
            if(rec++ > 3) break;
            clear();
            goto START_LOGIN;
        default:
            break;
        }
    }else{
		// service->soap_stream_fault(std::cerr);
    }

    throw LoginFailed(username.c_str(),  r.LoginResult);
}

void
Wrapesms::queue_msg(string mobile, string message){
    MUTEX_LOCK(_mutsms);
    // LDebug("queue_msg " << mobile << " msg:" << message );

    MSGPair mpair;
    mpair.set(mobile, message);
    _pmlist->push_back(mpair);
    // LDebug("queue_msg " << _pmlist->size());
    MUTEX_UNLOCK(_mutsms);
}

void
Wrapesms::putMsg(){

    if(_disabled) throw EsmsDisabled("putMsg");

    MUTEX_LOCK(_mutsms);

    if(_pmlist->empty()){
        MUTEX_UNLOCK(_mutsms);
        return;
    }
    
    MsgList::iterator itr;
    // getCurrentDate
    string curr_date;
    _ns1__getCurrentDate l;    
    _ns1__getCurrentDateResponse r;
    if(service->getCurrentDate(&l, &r) == SOAP_OK){
        curr_date = *(r.getCurrentDateResult);
        cout << "curr_date: "<< *(r.getCurrentDateResult) <<endl;
    }else{
        // service->soap_stream_fault(std::cerr);
        MUTEX_UNLOCK(_mutsms);        
        throw PutMsgFailed("getCurrentDate() fault");
        return;
    }

    if(curr_date.empty()){
        curr_date = _timestr();
        cout << "timestr: "<< curr_date <<endl;
    }

    // insertTaskTable
    _ns1__insertTaskTable l1;
    _ns1__insertTaskTableResponse r1;
    l1.CompanyCode = &servcode;
    l1.TaskCode = _getTaskCode();
    string content = "yitai";
    l1.Content = &content;
    l1.dStart = &curr_date;
    l1.i_USCOREallCount = _pmlist->size(); // required
    
    if(service->insertTaskTable(&l1, &r1) == SOAP_OK){
         bool res = r1.insertTaskTableResult;
         cout << "Taskcode: "<< l1.TaskCode << endl;
         cout << "Count: " << _pmlist->size() << endl;
         if(res == false){
             cout << "iinsertTasktable faile!" << endl;
             return;
         }
    }else{
        // service->soap_stream_fault(std::cerr);
        MUTEX_UNLOCK(_mutsms);        
        throw PutMsgFailed("insertTaskTable() Failed");
        return;
    }

    // sendMessageQueue
    _ns1__sendMessageQueue l2;
    _ns1__sendMessageQueueResponse r2;

    ns1__ArrayOfAnyType plist;
    ns1__ArrayOfAnyType clist;

    l2.CompanyCode = &servcode;
    l2.PhoneCollection = &plist;
    l2.Content = &clist;
    l2.PhoneCode = &phonecode;

    for(itr = _pmlist->begin(); itr != _pmlist->end(); itr++){ // for_each()??
        // insert phone number
        plist.anyType.push_back(itr->mobile);
        // insert corresponding message
        clist.anyType.push_back(_getContent(itr->message));
    }

    // TODO: should sync
    _pmlist->clear();
    MUTEX_UNLOCK(_mutsms);
        
    if(service->sendMessageQueue(&l2, &r2) == SOAP_OK){
         int res = r2.sendMessageQueueResult;
         if(res == 0) return; // success
    }else{
        // service->soap_stream_fault(std::cerr);
    }
    throw PutMsgFailed("sendMessageQueue() Failed");
}

MsgVector *
Wrapesms::getMsg(){

    if(_disabled) throw EsmsDisabled("getMsg");
    
    _ns1__getMOInfo l;
    _ns1__getMOInfoResponse r;

    l.CompanyCode = &servcode;
        
    if(service->getMOInfo(&l, &r) == SOAP_OK){
        ns1__ArrayOfAnyType* na = r.getMOInfoResult;

        if(NULL == na) {
            throw GetMsgFailed("getMOInfoResult is NULL");
        }
        
        // defined _XML (char*)
        vector<anyType_Type> nat = na->anyType;
        if(nat.empty()){
            throw GetMsgFailed("getMOInfoResult is Empty");
        }
        vector<anyType_Type>::iterator itr;
        anyType_Type msg;
        int p1, p2;
        MSGPair mpair;
        
        for(itr = nat.begin(); itr != nat.end(); itr++){
            msg = *itr;
            string msgstr(msg);
            p1 = msgstr.find(',');
            
            p2 = msgstr.rfind(',');
            
            // msgList[msgstr.substr(0, p1)] = second;
            mpair.set( msgstr.substr(0, p1), msgstr.substr(p2+1, string::npos) );
            _msgList.push_back(mpair);
        }
        return &_msgList;
    }else{
        // service->soap_stream_fault(std::cerr);
        throw GetMsgFailed("Soap stream fault when getMsg()");
    }
}

void
Wrapesms::clearGetMsgResult(){
    MsgVector::iterator itr;
    for(itr = _msgList.begin(); itr != _msgList.end(); ){
        _msgList.erase(itr++);
    }
}

void
Wrapesms::clear(){
    _ns1__ClearActiveUser l;
    _ns1__ClearActiveUserResponse r;
    l.code = &servcode;
    if(service->ClearActiveUser(&l, &r) != SOAP_OK){
		// service->soap_stream_fault(std::cerr);
    }
}

char*
Wrapesms::_timestr(){
    struct timeval tv;
    struct tm *tm;
    gettimeofday(&tv, NULL);
    tm = localtime(&tv.tv_sec);
    sprintf(dateStr, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
    return dateStr;
}

void
Wrapesms::push_msg(const char *optarg){
    using namespace boost::interprocess;
    
    try{
        managed_shared_memory segment(open_only, SHM_MSG_SEG);
        MsgList* mlist = segment.find<MsgList>(SHM_PUTMSG_OBJ).first;

        std::string str = optarg;
        std::string::size_type idx = str.find(",");
        std::string mobile = str.substr(0, idx);
        std::string message = str.substr(idx+1);

        MSGPair mpair(mobile, message);
        
        mlist->push_back(mpair);
    }
    catch(...){
        throw;
    }
}

void
Wrapesms::print_msglist(){
    using namespace boost::interprocess;
    using std::cout;
    using std::left;
    using std::setw;
    using std::setfill;
    using std::endl;
    
    try{
        managed_shared_memory segment(open_only, SHM_MSG_SEG);
        MsgList* mlist = segment.find<MsgList>(SHM_PUTMSG_OBJ).first;

        MsgList::iterator itr;

        cout << setw(14) << left << setfill(' ') << "Mobile no."        \
             << setw(70) << left << setfill(' ') << "Message"   << endl;
            
        for(itr = mlist->begin(); itr != mlist->end(); ++itr){
            cout << setw(14) << left << setfill(' ') << itr->mobile     \
                 << setw(70) << left << setfill(' ') << itr->message  << endl;
        }
    }
    catch(...){
        throw;
    }    
}

void
Wrapesms::push_msgvector(MsgVector &mvs){
    using namespace boost::interprocess;
    
    try{
        managed_shared_memory segment(open_only, SHM_MSG_SEG);
        MsgList* mlist = segment.find<MsgList>(SHM_PUTMSG_OBJ).first;

        MSGPair mpair;
        
        MsgVector::iterator itr;
        for(itr = mvs.begin(); itr != mvs.end(); ++itr ){
            mpair.set(itr->mobile, itr->message);
            mlist->push_back(mpair);
        }
    }
    catch(...){
        throw;
    }    
}
